﻿using System;
using System.Diagnostics;
using System.ServiceProcess;
using Microsoft.Win32;
using System.IO;
using System.Security;
using System.Net.Mail;
using System.Net;
using System.Threading;
using System.Security.Cryptography;
using System.Text;
using System.Collections.Generic;
using System.Management;

namespace AleScheduler_service
{
    public partial class AleScheduler_Service : ServiceBase
    {
        private System.Threading.Timer timer;
        private System.Threading.Timer timerSettings;
        private volatile Dictionary<string, Dictionary<string, string>> aSettings;   //Application Settings
        private volatile Dictionary<string, ulong> launchCounter;                       
        ManagementEventWatcher startWatchProcess;                                    //StartProcess Monitor object
        ManagementEventWatcher stopWatchProcess;                                     //stopProcess Monitor object
        private ulong passedSec = 0;                                                 //Counter of the elapsed seconds
        static readonly object _locker = new object();                               //Object for Locking in Thread safe
        private string sSource = "AleScheduler_Service";
        private string sLog = "Application";

        public enum commands
        {
            HUP = 129 //Reload Configuration of the Service
        }

        public AleScheduler_Service()
        {
            InitializeComponent();    
        }
        //Declarations of Some Useful Property
        #region Service_Propery
        private int ucount;
        public int userCount
        {
            get { return ucount; }
            set { ucount = value; }
        }
        #endregion

        protected override void OnStart(string[] args)
        {
            //Initialize Main Associative Array - aSettings
            aSettings = new Dictionary<string, Dictionary<string, string>>();
            //Get the number of the logged in user on the system
            this.userCount = getNumberofLoggedUser();
            //Create the event log source if not exist
            if (!EventLog.SourceExists(sSource)) EventLog.CreateEventSource(sSource, sLog);
            //Initialize Setting Timer (Read Settings from Registry and store it in Associative Array)
            //Every 5 minutes check for change in Registry configuration
            System.Threading.TimerCallback oCallbackSettings = new System.Threading.TimerCallback(SettingsTimer_Tick);
            timerSettings = new System.Threading.Timer(oCallbackSettings, null,0,300000);
            //Initialize the Main Timer 
            System.Threading.TimerCallback oCallback = new System.Threading.TimerCallback(ServiceTimer_Tick);
            timer = new System.Threading.Timer(oCallback, null, 1000, 1000);
            //Initialize launchCounter
            launchCounter = new Dictionary<string, ulong>();
            //Start the FileSystemWatcher
            new Thread(new ThreadStart(startFileSystemWatcher)).Start();

            //Initialize and Start the Process Watcher
            inizializeProcessWatcher();
        }

        private void inizializeProcessWatcher() {
            try {
                startWatchProcess = new ManagementEventWatcher(new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
                startWatchProcess.EventArrived += new EventArrivedEventHandler(startWatchProcess_EventArrived);
                startWatchProcess.Start();
            } catch (Exception e) {
                EventLog.WriteEntry(sSource, "Error starting Start Process Watcher : " + e.Message + Environment.NewLine +
                    "StackTrace : " + Environment.NewLine + e.StackTrace, EventLogEntryType.Error);
            }

            try {
                stopWatchProcess = new ManagementEventWatcher(new WqlEventQuery("SELECT * FROM Win32_ProcessStopTrace"));
                stopWatchProcess.EventArrived += new EventArrivedEventHandler(stopWatchProcess_EventArrived);
                stopWatchProcess.Start();
            } catch (Exception e) {
                EventLog.WriteEntry(sSource, "Error starting Stop Process Watcher : " + e.Message + Environment.NewLine +
                    "StackTrace : " + Environment.NewLine + e.StackTrace, EventLogEntryType.Error);
            }
        }

        protected override void OnStop()
        {
            //Disposing Service Timer
            timerSettings.Dispose();
            timer.Dispose();
            //Stop the Process Monitor
            stopWatchProcess.Stop();
            startWatchProcess.Stop();
        }

        #region Crypto_Functions
       
        public string DecryptPassword(string cipherText,
                                     string passPhrase,
                                     string saltValue,
                                     string hashAlgorithm,
                                     int passwordIterations,
                                     string initVector,
                                     int keySize) {
            // Convert strings defining encryption key characteristics into byte
            // arrays. Let us assume that strings only contain ASCII codes.
            // If strings include Unicode characters, use Unicode, UTF7, or UTF8
            // encoding.
            byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
            byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);

            // Convert our ciphertext into a byte array.
            byte[] cipherTextBytes = Convert.FromBase64String(cipherText);

            // First, we must create a password, from which the key will be 
            // derived. This password will be generated from the specified 
            // passphrase and salt value. The password will be created using
            // the specified hash algorithm. Password creation can be done in
            // several iterations.
            PasswordDeriveBytes password = new PasswordDeriveBytes(
                                                            passPhrase,
                                                            saltValueBytes,
                                                            hashAlgorithm,
                                                            passwordIterations);

            // Use the password to generate pseudo-random bytes for the encryption
            // key. Specify the size of the key in bytes (instead of bits).
            byte[] keyBytes = password.GetBytes(keySize / 8);

            // Create uninitialized Rijndael encryption object.
            RijndaelManaged symmetricKey = new RijndaelManaged();

            // It is reasonable to set encryption mode to Cipher Block Chaining
            // (CBC). Use default options for other symmetric key parameters.
            symmetricKey.Mode = CipherMode.CBC;

            // Generate decryptor from the existing key bytes and initialization 
            // vector. Key size will be defined based on the number of the key 
            // bytes.
            ICryptoTransform decryptor = symmetricKey.CreateDecryptor(
                                                             keyBytes,
                                                             initVectorBytes);

            // Define memory stream which will be used to hold encrypted data.
            MemoryStream memoryStream = new MemoryStream(cipherTextBytes);

            // Define cryptographic stream (always use Read mode for encryption).
            CryptoStream cryptoStream = new CryptoStream(memoryStream,
                                                          decryptor,
                                                          CryptoStreamMode.Read);

            // Since at this point we don't know what the size of decrypted data
            // will be, allocate the buffer long enough to hold ciphertext;
            // plaintext is never longer than ciphertext.
            byte[] plainTextBytes = new byte[cipherTextBytes.Length];

            // Start decrypting.
            int decryptedByteCount = cryptoStream.Read(plainTextBytes,
                                                       0,
                                                       plainTextBytes.Length);

            // Close both streams.
            memoryStream.Close();
            cryptoStream.Close();

            // Convert decrypted data into a string. 
            // Let us assume that the original plaintext string was UTF8-encoded.
            string plainText = Encoding.UTF8.GetString(plainTextBytes,
                                                       0,
                                                       decryptedByteCount);

            // Return decrypted string.   
            return plainText;
        }

        #endregion

        #region Sendmail_Method
        private bool SendMailStart(string nameschedule, string error) {
            //Get Variable from Regestry
            RegistryKey reg = Registry.LocalMachine.OpenSubKey("Software", true).OpenSubKey("AleScheduler", true).OpenSubKey("MailConfig", true);

            string host = (string)reg.GetValue("SMTPServer");
            int port = Convert.ToInt32(reg.GetValue("SMTPServerPort"));
            string userName = (string)reg.GetValue("Username");
            string pswd = (string)reg.GetValue("Password");
            string fromAddress = (string)reg.GetValue("FromMail");
            string toAddress = (string)reg.GetValue("ToMAil");
            bool SSL = Convert.ToBoolean((string)reg.GetValue("SSL-TLS", false));
            string body = "Schedule : " + nameschedule + ", failed starting up \nERROR : \n" + error;
            string subject =  nameschedule + " Schedule Failed!";

            //  Create a MailMessage object with a from and to address
            using (MailMessage msg = new MailMessage(new MailAddress(fromAddress, "AleScheduler"), new MailAddress(toAddress))) {
                msg.Subject = subject;  //  Add your subject
                msg.SubjectEncoding = System.Text.Encoding.UTF8;
                msg.Body = body;    //  Add the body of your message
                msg.BodyEncoding = System.Text.Encoding.UTF8;
                msg.IsBodyHtml = false; //  Does the body contain html

                SmtpClient client = new SmtpClient(host, port); //  Create an instance of SmtpClient with your smtp host and port
                if (userName != string.Empty && pswd != string.Empty) {
                    #region Decript Crypted password
                    string passPhrase = "Pas5pr@seé08kk";         // can be any string
                    string saltValue = "s@1tValue55bb54";         // can be any string
                    string hashAlgorithm = "SHA1";                // can be "MD5"
                    int passwordIterations = 2;                   // can be any number
                    string initVector = "@1B2c3D4e5F6g7H8";       // must be 16 bytes
                    int keySize = 256;                            // can be 192 or 128
                    string decryptedpass = DecryptPassword(pswd, passPhrase,
                                                              saltValue,
                                                              hashAlgorithm,
                                                              passwordIterations,
                                                              initVector,
                                                              keySize);

                    #endregion
                    client.Credentials = new NetworkCredential(userName, decryptedpass); //  Assign your username and password to connect to gmail
                    client.EnableSsl = SSL;  //  Enable SSL
                }

                try {
                    client.Send(msg);//  Try to send your message
                    return true;
                } catch (Exception ex) {
                    if (!EventLog.SourceExists(sSource))
                        EventLog.CreateEventSource(sSource, sLog);

                    EventLog.WriteEntry(sSource, "(Task : " + nameschedule + ")" + "Unable to Send eMail to System Administrator : " +
                        toAddress + "!\nError Information : \n" + ex.Message, EventLogEntryType.Error);
                    return false;
                }
            }
        }
        #endregion

        #region Start_Scheduletions_Process

        private bool Start_Scheduletions_Process(bool forceInteractWithDesktop, string strName, string strExeName, string pathexe, string strArgument, bool Sendmail, uint timeOut, bool LogText, string LogPath,uint WindowMode)
        {
            string errormessage = string.Empty;
            const int ERROR_FILE_NOT_FOUND = 2;
            const int ERROR_ACCESS_DENIED = 5;
            if (forceInteractWithDesktop)
            {
                //Launch Process as a User API for Force Interact with Desktop
                //Useful for force program to Interact wiith Desktop in Windows Vista/7/Server 2008
                if (!string.IsNullOrEmpty(strArgument))
                    AleUtil.ProcessAsUser.Launch(strExeName + " " + strArgument,WindowMode);
                else
                    AleUtil.ProcessAsUser.Launch(strExeName,WindowMode);

                //Log Process Starting
                log(LogText,"(Task : " + strName + ")Start Process : " + strExeName + " (process forced to Interact with Desktop)",EventLogEntryType.SuccessAudit,strName,LogPath);
            }
            else
            {
                Process process = new Process();
                ProcessStartInfo startInfo = new ProcessStartInfo();
                try
                {
                    process.StartInfo = startInfo;
                    startInfo.FileName = strExeName;
                    startInfo.WorkingDirectory = pathexe;
                    if (!string.IsNullOrEmpty(strArgument))
                        startInfo.Arguments = strArgument;
                    startInfo.UseShellExecute = true;
                    //Window Mode Check
                    if (WindowMode == 5)             //Minimized Window
                        startInfo.WindowStyle = ProcessWindowStyle.Minimized;
                    else if (WindowMode == 4)        //Maximized Window
                        startInfo.WindowStyle = ProcessWindowStyle.Maximized;
                    else if (WindowMode == 3)        //Hidden Window
                        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
                    else if (WindowMode == 2)        //NO Window
                        startInfo.CreateNoWindow = true;

                    if (process.Start() == true)
                        log(LogText,"(Task : " + strName + ")Process Started Succesfully " + startInfo.FileName,EventLogEntryType.SuccessAudit,strName,LogPath);
                    

                    #region Wait for the process Time Out.
                    if (timeOut > 0)
                    {
                        process.WaitForExit(Convert.ToInt32(timeOut));
                        //Check to see if the process is still running.
                        if (process.HasExited == false)
                            //Process is still running.
                            //Test to see if the process is hung uprocess.
                            if (process.Responding)
                                //Process was responding; close the main window.
                                process.CloseMainWindow();
                            else
                                //Process was not responding; force the process to close.
                                process.Kill();
                    }
                    #endregion
                }
                catch (System.ComponentModel.Win32Exception e)
                {

                    if (e.NativeErrorCode == ERROR_FILE_NOT_FOUND)
                    {
                        errormessage = "(Task : " + strName + ") " + e.Message + ". Check the path of Schedulation entry : " + strName + ".";
                        log(LogText, errormessage, EventLogEntryType.Error, strName, LogPath);
                        if (Sendmail && SendMailStart(strName, errormessage))
                            log(LogText, "Execution exeception notification eMail sent", EventLogEntryType.Information, strName, LogPath);

                        return false;
                    }
                    else if (e.NativeErrorCode == ERROR_ACCESS_DENIED)
                    {
                        errormessage = "(Task : " + strName + ") " + e.Message + ". You do not have permission to execute : " + strExeName + ".";
                        log(LogText, errormessage, EventLogEntryType.Error, strName, LogPath);
                        if (Sendmail && SendMailStart(strName, errormessage))
                            log(LogText, "Execution exeception notification eMail sent", EventLogEntryType.Information, strName, LogPath);

                        return false;
                    }
                    else
                    {
                        errormessage = "(Task : " + strName + ") " + e.Message +
                            ". Generic error for execute : " + strExeName + ".\nOther Useful Information : \n" +
                        "Error Code : " + e.ErrorCode.ToString() + "\n" +
                        "Stack Trace : \n" + e.StackTrace;
                        log(LogText, errormessage, EventLogEntryType.Error, strName, LogPath);
                        if (Sendmail && SendMailStart(strName, errormessage))
                            log(LogText, "Execution exeception notification eMail sent", EventLogEntryType.Information, strName, LogPath);

                        return false;
                    }
                }
                catch (Exception g)
                {
                    errormessage = "(Task : " + strName + ") Generic Schedulations Execution Failure :\n" +
                        "Schedulations Name : " + strName + "\n" +
                        "Error Information :\n" + g.Message;
                    log(LogText, errormessage, EventLogEntryType.Error, strName, LogPath);
                    if (Sendmail && SendMailStart(strName, errormessage))
                        log(LogText, "Execution exeception notification eMail sent", EventLogEntryType.Information, strName, LogPath);

                    return false;
                }
            }
            return true;
        }
        #endregion

        private void refreshConfig()
        {
            bool updated = false;
           //Refresh in-Memory Configuration with the value loaded from registry Key
            try
            {
                do {
                    //Try to get the exclusive control of the object locker
                    if (Monitor.TryEnter(_locker, TimeSpan.FromSeconds(3))) {
                        try {
                            //Clear Main Associative Array - aSettings
                            aSettings.Clear();

                            //Refresh Service Configuration (Read Settings from Registry Key)

                            //Try to read the value from the windows registry
                            using (RegistryKey key = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("AleScheduler")) {
                                if (key == null) {
                                    EventLog.WriteEntry("Unable to open the registry AleScheduler for 'AleScheduler'", EventLogEntryType.Error);
                                    return;
                                }

                                string[] subKeys = null;
                                try {
                                    subKeys = key.GetSubKeyNames();
                                } catch (SecurityException secExp) {
                                    EventLog.WriteEntry("Security exception thrown getting the sub keys names " + secExp.Message, EventLogEntryType.Error);
                                    return;
                                } catch (IOException ioExp) {
                                    EventLog.WriteEntry("IO exception thrown getting the sub key names " + ioExp.Message, EventLogEntryType.Error);
                                    return;
                                }

                                //Loop for examine every Schedulations item in the registry
                                foreach (string strName in subKeys) {

                                    //Open Regestry SubKey
                                    using (RegistryKey subKey = key.OpenSubKey(strName, false)) {
                                        if ((subKey == null) || (strName == "MailConfig"))
                                            continue;
                                        //Add a sub array  
                                        Dictionary<string, string> arrChd = new Dictionary<string, string>();                                                             //Executed flag for Schedulations
                                        arrChd.Add("FileToRun", subKey.GetValue("FileToRun").ToString());                              //File to Run Setting
                                        arrChd.Add("ScheduleType", subKey.GetValue("ScheduleType").ToString());                        //Schedulation Type
                                        arrChd.Add("Time", subKey.GetValue("Time", string.Empty).ToString());
                                        arrChd.Add("Day", subKey.GetValue("Day", string.Empty).ToString());
                                        arrChd.Add("Every_Time", subKey.GetValue("Every_Time", 0).ToString());
                                        arrChd.Add("Time_Range", subKey.GetValue("Time_Range", 0).ToString());
                                        arrChd.Add("SendMail", subKey.GetValue("SendMail", "False").ToString());
                                        arrChd.Add("Disabled", subKey.GetValue("Disabled", "False").ToString());
                                        arrChd.Add("PathEXE", subKey.GetValue("PathEXE", string.Empty).ToString());
                                        arrChd.Add("Arguments", subKey.GetValue("Arguments", string.Empty).ToString());
                                        arrChd.Add("Timeout", subKey.GetValue("Timeout", 0).ToString());
                                        arrChd.Add("TriggerTest", subKey.GetValue("TriggerTest", 0).ToString());
                                        arrChd.Add("LogFiles", subKey.GetValue("LogFiles", "False").ToString());
                                        arrChd.Add("LogDirectory", subKey.GetValue("LogDirectory", string.Empty).ToString());
                                        arrChd.Add("ForceInteractWithDesktop", subKey.GetValue("ForceInteractWithDesktop", "False").ToString());
                                        arrChd.Add("NumberOfTimes", subKey.GetValue("NumberOfTimes", 0).ToString());                   //Parameter for Repeated Schedulations
                                        arrChd.Add("HStartPeriod", (string)subKey.GetValue("HStartPeriod", string.Empty));
                                        arrChd.Add("HStopPeriod", (string)subKey.GetValue("HStopPeriod", string.Empty));
                                        arrChd.Add("WatcherType", subKey.GetValue("WatcherType", 0).ToString());
                                        arrChd.Add("WatchFileDir", subKey.GetValue("WatchFileDir", string.Empty).ToString());
                                        arrChd.Add("WindowMode", subKey.GetValue("WindowMode", 1).ToString());
                                        arrChd.Add("OnSessionChange", subKey.GetValue("OnSessionChange", 0).ToString());

                                        //Add SubArry to Main Array
                                        aSettings.Add(strName, arrChd);

                                    } //End of the subKey using
                                } //End of the for loop block
                                //Close Main Registry Key
                            }//Close using of the main registry key

                            //Set the flag of updated Configuration
                            updated = true;
                        } finally {
                            Monitor.Exit(_locker);
                        }
                    }
                } while (!updated);
            }
            catch (Exception ex)
            {
                System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
                if (!EventLog.SourceExists(sSource))
                    EventLog.CreateEventSource(sSource, sLog);

                EventLog.WriteEntry(sSource,"Error reloading configuration from registry : " + ex.Message + Environment.NewLine +
                    string.Format("Function : {0}, Line : {1}, Column : {2}", trace.GetFrame(0).GetMethod().Name, trace.GetFrame(0).GetFileLineNumber(), trace.GetFrame(0).GetFileColumnNumber()) + Environment.NewLine +
                    "StackTrace : " + Environment.NewLine + ex.StackTrace, EventLogEntryType.Error);
            }
        }

        private void SettingsTimer_Tick(object state)
        {
            /*Settings Timer :
             * This Timer get settings from Windows Registry Keys and store it in an
             * Associative Array Object : aSettings
            */
            refreshConfig();
        }

        private void ServiceTimer_Tick(object state)
        {
            lock (_locker)
            {
                //Main timer that check for task 
                try
                {
                    //Loop for examine every Schedulations item in the regestry
                    foreach (KeyValuePair<string, Dictionary<string, string>> strName in aSettings)
                    {
                        string name = strName.Key;
                        Dictionary<string, string> tmp = strName.Value;

                        // Check_Disabled_Schedulations
                        bool Disabled = Convert.ToBoolean(tmp["Disabled"]);
                        if (Disabled) continue;

                        //Declarations of needed Variables
                        string strExeName = tmp["FileToRun"];
                        string schType = tmp["ScheduleType"];
                        Int16 schitype = Convert.ToInt16(schType);
                        string strDay = tmp["Day"];
                        string strEvery = tmp["Every_Time"];
                        bool TextLog = Convert.ToBoolean(tmp["LogFiles"]);
                        string PathLogTextFiles = tmp["LogDirectory"];
                        DateTime dtTime = (isValidDate(strDay)) ? DateTime.Parse(strDay + " " + tmp["Time"]) : DateTime.Parse(tmp["Time"]);
                        DateTime now = DateTime.Now;

                            //Start of Check for Kind Of Schedulations
                            switch (schitype)
                            {
                                case 1:
                                case 4:
                                    //Code for Daily Schedulations - OK
                                    if (Math.Abs((now - dtTime).TotalSeconds) < 0.5)
                                        startSchedulation(name, tmp,true);

                                    break;
                                case 2:
                                    //Code for Weekly Schedulations - OK
                                    if (((now.DayOfWeek.ToString() == strDay) && (Math.Abs((now - dtTime).TotalSeconds) < 0.5)))
                                        startSchedulation(name, tmp,true);
                                    
                                    break;
                                case 3:
                                    //Code for Monthly Scheduled(Case 3) - OK
                                    if ((now.Day == dtTime.Day) && (Math.Abs((now.TimeOfDay - dtTime.TimeOfDay).TotalSeconds)) < 0.5)
                                        startSchedulation(name, tmp,true);
                                    
                                    break;
                                case 5:
                                    //Code for Reapeted Schedulations
                                    if (!(passedSec == 0))
                                    {
                                        ulong evMin = Convert.ToUInt64(strEvery);
                                        //if the mod of division PassedMin / evMin is zero launch the process
                                        if ((passedSec % evMin) == 0)
                                        {
                                            //Initialize some Variable
                                            ulong numberoftimes = Convert.ToUInt64(tmp["NumberOfTimes"]);
                                            ulong lcValue;
                                            bool lcExist = launchCounter.TryGetValue(strName.Key, out lcValue);
                                            string startTime = tmp["HStartPeriod"];
                                            string stopTime = tmp["HStopPeriod"];
                                            if (Test_Passed_Times(numberoftimes, lcValue) && Test_Period_Time(startTime, stopTime))
                                            {
                                                //Activating logging only if there is a hour repated schedulations
                                                int wRange = Convert.ToInt32(tmp["Time_Range"]);
                                                bool wLog = (wRange == 2) ? true : false;
                                                //Start The Schedulation
                                                startSchedulation(name, tmp, wLog);
                                            }
                                            //Set Value For Passed Times in Memory
                                            if (numberoftimes > 0)
                                            {
                                                if (!lcExist)
                                                    launchCounter.Add(strName.Key, 1);

                                                launchCounter[strName.Key] = lcValue + 1;
                                            }
                                        }
                                    }
                                    break;
                                case 6:
                                    //Reserved to OnSession change Schedulation !
                                    break;
                                case 7:
                                    //Reserved to FileSystemWatcher Schedulation !
                                    break;
                                case 8:
                                    //Reserved to Process Watcher Schedulation !
                                    break;
                                default:
                                    //Code for generic error Key not found 
                                    log(TextLog, "(Task : " + name + ")Type of Schedule not Found ! Seems there are problem with key of Schedulation in regestry!", EventLogEntryType.Warning, name, PathLogTextFiles);
                                    break;
                            }
                            //End of Check for Kind Schedulations

                        //Check if is Midnight reset the launchCounter
                        if ((now.Hour == 0 && now.Minute == 0 && now.Second == 0) || (now.Hour == 0 && now.Minute == 0 && now.Second == 1))
                            launchCounter.Clear();
                    }

                }
                catch (Exception ex)
                {
                    System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
                    if (!EventLog.SourceExists(sSource))
                        EventLog.CreateEventSource(sSource, sLog);

                    EventLog.WriteEntry(sSource, "Error during task check : " + ex.Message + Environment.NewLine +
                        string.Format("Function : {0}, Line : {1}, Column : {2}", trace.GetFrame(0).GetMethod().Name, trace.GetFrame(0).GetFileLineNumber(), trace.GetFrame(0).GetFileColumnNumber()) + Environment.NewLine +
                        "StackTrace : " + Environment.NewLine + ex.StackTrace, EventLogEntryType.Error);
                }
                finally
                {
                    //Every Timer Tick increment of 1 elapsed second
                    passedSec++;
                }
            }
        }

        private void startSchedulation(string name,Dictionary<string, string> tmp, bool toLog) {

            string strExeName = tmp["FileToRun"];
            bool ForceToInteractWithDesktop = Convert.ToBoolean(tmp["ForceInteractWithDesktop"]);
            string PathLogTextFiles = tmp["LogDirectory"];
            string pathexe = tmp["PathEXE"];
            string argument = tmp["Arguments"];
            uint TriggerTest = Convert.ToUInt32(tmp["TriggerTest"]);
            bool TextLog = Convert.ToBoolean(tmp["LogFiles"]);
            bool SendMail = Convert.ToBoolean(tmp["SendMail"]);
            uint timeOut = Convert.ToUInt32(tmp["Timeout"]);
            uint WindowMode = Convert.ToUInt32(tmp["WindowMode"]);

                        //Create a new Thread for Each File to Schedule (if there's a Wildcard character)
                        foreach (FileInfo fileToExec in listFilesInExecutable(strExeName)) {
                                Thread t = new Thread(delegate() { Start_Scheduletions_Process(ForceToInteractWithDesktop, name, fileToExec.FullName, pathexe, argument, SendMail, timeOut, TextLog, PathLogTextFiles, WindowMode); });
                                string trgName = string.Empty;

                                if (TriggerTest == 0)
                                    t.Start();
                                else {
                                    //Code For Check Trigger if the TriggerTest flag = TRUE
                                    if (Trigger_Test(name, ref trgName))
                                        t.Start();
                                    else {
                                        if (toLog)
                                            log(TextLog, "(Task : " + name + ")Couldn't Start Task : " + name + " ! Due to Trigger Number " + trgName + " Test Failed!", EventLogEntryType.FailureAudit, name, PathLogTextFiles);
                                    }
                                }
                            }
        
        }

        private void startFileSystemWatcher()
        {
            //Start the file system Watcher for specified Schedulation
            //Waiting for aSettings
            Thread.Sleep(1500);

            try {
                //Loop for examine every Schedulations item in the in Memory Settings
                foreach (KeyValuePair<string, Dictionary<string, string>> strName in aSettings) {
                    Dictionary<string, string> tmp = strName.Value;
                    Int16 schtype = Convert.ToInt16(tmp["ScheduleType"]);
                    //If readed Schedulation is FileSystemWatcher Schedulation
                    if (schtype == 7) {
                        int type = int.Parse(tmp["WatcherType"]);
                        FileSystemWatcher watcher = new FileSystemWatcher();
                        //Get Type of file watcher type
                        string watchType = "Unknown Event";
                        switch (type) {
                            case 1:
                                watchType = "Changed Event";
                                break;
                            case 2:
                                watchType = "Created Event";
                                break;
                            case 3:
                                watchType = "Deleted Event";
                                break;
                            case 4:
                                watchType = "Renamed Event";
                                break;
                        }

                        //Reading FileSystemWatcher Schedulation Settings
                        string filew = System.IO.Path.GetFileName(tmp["WatchFileDir"]);
                        string dirw = System.IO.Path.GetDirectoryName(tmp["WatchFileDir"]);
                        watcher.Filter = filew;
                        watcher.IncludeSubdirectories = false;
                        watcher.Path = dirw;

                        // Add event handlers
                        watcher.Changed += new FileSystemEventHandler(whatcher_fileEvent);
                        watcher.Created += new FileSystemEventHandler(whatcher_fileEvent);
                        watcher.Deleted += new FileSystemEventHandler(whatcher_fileEvent);
                        watcher.Renamed += new RenamedEventHandler(whatcher_fileEvent);
                        // This One is created when it detects an error.
                        watcher.Error += new ErrorEventHandler(whatcher_WatcherError);

                        // Begin watching.
                        watcher.EnableRaisingEvents = true;

                        //Log into Windows eventLog
                        if (!EventLog.SourceExists(sSource))
                            EventLog.CreateEventSource(sSource, sLog);

                        EventLog.WriteEntry(sSource, string.Format("FileSystemWatcher started watching Dir : {1}, File : {2}, Type : {0}", watchType, dirw, filew), EventLogEntryType.Information);
                    }
                }

            } catch (Exception ex) {
                EventLog.WriteEntry(sSource, "Error initializing FileSystem watchers : " + ex.Message + " \n\nStackTrace :\n " + ex.StackTrace, EventLogEntryType.Error);
            }
        }


        // The FileWatcher error event handler
        // this error usually happen when watcher point 
        // to a network shared connection
        private void whatcher_WatcherError(object source, ErrorEventArgs e) {
          FileSystemWatcher watcher = (FileSystemWatcher)source;

         Exception watchException = e.GetException();
         EventLog.WriteEntry(sSource, "A FileSystemWatcher error has occurred: "
                         + watchException.Message,EventLogEntryType.Error);
         //Save path and Filter of old watcher object
         string wPath = watcher.Path;
         string wExt = watcher.Filter;
         // We need to create new version of the object because the
         // old one is now corrupted
         watcher = new FileSystemWatcher();
         while (!watcher.EnableRaisingEvents)
         {
            try
            {
               // This will throw an error at the
               // watcher.NotifyFilter line if it can't get the path.
               reWatchFile(watcher,wPath,wExt);
                //Log that the file Watcher has been reloaded
                EventLog.WriteEntry(sSource,"FileSystemWatcher reloaded after error" + Environment.NewLine +
                    string.Format("watching Dir : {1}, File : {2}", wPath,wExt), EventLogEntryType.Information);
            }
            catch
            {
               // Sleep for a bit; otherwise, it takes a bit of
               // processor time
               System.Threading.Thread.Sleep(5000);
            }
         }
      }

        /// <summary>
        /// Rewatch event that fires in case of error of the watcher
        /// </summary>
        /// <param name="watcher">FileSystemWatcher event</param>
        /// <param name="path">Path to watch</param>
        /// <param name="ext">Name or mask of the file to watch</param>
        private void reWatchFile(FileSystemWatcher watcher,string path,string ext) {

            watcher.Path = path;
            watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
            watcher.Filter = ext;

            // Add event handlers
            watcher.Changed += new FileSystemEventHandler(whatcher_fileEvent);
            watcher.Created += new FileSystemEventHandler(whatcher_fileEvent);
            watcher.Deleted += new FileSystemEventHandler(whatcher_fileEvent);
            watcher.Renamed += new RenamedEventHandler(whatcher_fileEvent);
            // This One is created when it detects an error.
            watcher.Error += new ErrorEventHandler(whatcher_WatcherError);

            // Begin watching.
            watcher.EnableRaisingEvents = true;
        }

        private void whatcher_fileEvent(object sender, FileSystemEventArgs e)
        {
            int typeHappened = 0;
            string sKindWatcher = "Unknown Event";
            switch (e.ChangeType)
            {
                case WatcherChangeTypes.Changed:
                    //File Changed FileSystemWatcher
                    typeHappened = 1;
                    sKindWatcher = "Changed Event";
                    break;
                case WatcherChangeTypes.Created:
                    //File Created FileSystemWatcher
                    typeHappened = 2;
                    sKindWatcher = "Created Event";
                    break;
                case WatcherChangeTypes.Deleted:
                    //File Deleted FileSystemWatcher
                    sKindWatcher = "Deleted Event";
                    typeHappened = 3;
                    break;
                case WatcherChangeTypes.Renamed:
                    //File Renamed FileSystemWatcher
                    typeHappened = 4;
                    sKindWatcher = "Renamed Event";
                    break;
                    
            }

          #if (DEBUG)
                EventLog.WriteEntry(sSource, "New FileSystemWatcher fired !" + Environment.NewLine +
                "Type : " + sKindWatcher, EventLogEntryType.Information);
          #endif

            if(Monitor.TryEnter(_locker,TimeSpan.FromSeconds(5))) {
            //Read if there is a schedulation for this event
            try {
                //Loop for examine every Schedulations item in the in Memory Settings
                foreach (KeyValuePair<string, Dictionary<string, string>> strName in aSettings) {
                    Dictionary<string, string> tmp = strName.Value;
                    Int16 schtype = Convert.ToInt16(tmp["ScheduleType"]);
                    //If readed Schedulation is FileSystemWatcher Schedulation
                    if (schtype == 7) {
                        string strExeName = tmp["FileToRun"];
                        int type = int.Parse(tmp["WatcherType"]);
                        //Check First what kind of event has happened 
                        if (typeHappened == type && checkIfFileinWatcher(tmp["WatchFileDir"].Trim(), e.Name)) {
                            bool ForceToInteractWithDesktop = Convert.ToBoolean(tmp["ForceInteractWithDesktop"]);
                            uint timeOut = Convert.ToUInt32(tmp["Timeout"]);
                            uint WinMode = Convert.ToUInt32(tmp["WindowMode"]);
                            uint TriggerTest = Convert.ToUInt32(tmp["TriggerTest"]);
                            bool TextLog = Convert.ToBoolean(tmp["LogFiles"]);
                            bool SendMail = Convert.ToBoolean(tmp["SendMail"]);
                            bool Disabled = Convert.ToBoolean(tmp["Disabled"]);
                            //Check Triggers and eventually start Schedulations
                            if (!Disabled && (TriggerTest == 0 || Trigger_Test(strName.Key))) {
                                //Start Schedulation Process in a New Thread
                                foreach (FileInfo fileToExec in listFilesInExecutable(strExeName))
                                    new Thread(delegate() { Start_Scheduletions_Process(ForceToInteractWithDesktop, strName.Key, fileToExec.FullName, tmp["PathEXE"], tmp["Arguments"], SendMail, timeOut, TextLog, tmp["LogDirectory"], WinMode); }).Start();
                            }
                        }
                    }
                }
            } catch (Exception ex) {
                System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
                EventLog.WriteEntry(sSource, "Error on file watcher event : " + ex.Message + Environment.NewLine +
                    "Type : " + sKindWatcher + Environment.NewLine +
                    string.Format("Function : {0}, Line : {1}, Column : {2}", trace.GetFrame(0).GetMethod().Name, trace.GetFrame(0).GetFileLineNumber(), trace.GetFrame(0).GetFileColumnNumber()) + Environment.NewLine +
                    "StackTrace : " + Environment.NewLine + ex.StackTrace, EventLogEntryType.Error);
            } finally {
                Monitor.Exit(_locker);
            }
        }  //end of Try Enter Monitor lock
        }

        private bool checkIfFileinWatcher(string fileOrMask,string fileFound)
        {
            string path = System.IO.Path.GetDirectoryName(fileOrMask);
            string file = System.IO.Path.GetFileName(fileOrMask);
            if (!string.IsNullOrEmpty(path) && !string.IsNullOrEmpty(file))
            {
                DirectoryInfo dir = new DirectoryInfo(path);
                FileInfo[] files = dir.GetFiles(file);
                foreach (FileInfo fileToTest in files)
                {
                    if (String.Equals(fileToTest.Name, fileFound,StringComparison.OrdinalIgnoreCase))
                        return true;
                }
            }
            else if ((!string.IsNullOrEmpty(path) && System.IO.Directory.Exists(path)) && string.IsNullOrEmpty(file))
                return true;

            return false;
        }

        private int getNumberofLoggedUser()
        {
            int number = 0;
            try
            {
                ManagementScope ms = new ManagementScope(ManagementPath.DefaultPath);
                System.Management.ManagementObject o;
                SelectQuery q = new SelectQuery("Win32_LoggedOnUser"); // only interactive logons
                ManagementObjectSearcher query = new ManagementObjectSearcher(ms, q);

                ManagementObjectCollection queryCollection = query.Get();

                foreach (ManagementObject mo in queryCollection)
                {
                    o = new ManagementObject(mo["Dependent"].ToString());
                    if ((o["LogonType"].ToString()) == "2") // is interactive?
                        number++;

                    mo.Dispose();
                    o.Dispose();
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
                if (!EventLog.SourceExists(sSource))
                    EventLog.CreateEventSource(sSource, sLog);

                EventLog.WriteEntry(sSource,"Error retrieving number of logged user on the system : " + ex.Message + Environment.NewLine +
                    string.Format("Function : {0}, Line : {1}, Column : {2}", trace.GetFrame(0).GetMethod().Name, trace.GetFrame(0).GetFileLineNumber(), trace.GetFrame(0).GetFileColumnNumber()) + Environment.NewLine +
                    "StackTrace : " + Environment.NewLine + ex.StackTrace, EventLogEntryType.Error);
            }
            return number;
        }

        #region Trigger_Test_Func
        public bool Trigger_Test(string schName) {
            string ale = "ale";
            return Trigger_Test(schName, ref ale);
        }

        public bool Trigger_Test(string schName, ref string trgname)
        {
            //Main Try - Catch block
            try {

                using (RegistryKey reg = Registry.LocalMachine.OpenSubKey("Software", false).OpenSubKey("AleScheduler", false).OpenSubKey(schName, false)) {
                    RegistryKey subKey;
                    string[] subKeys = reg.GetSubKeyNames();
                    foreach (string strName in subKeys) {
                        subKey = reg.OpenSubKey(strName);
                        if (subKey == null || (strName == "MailConfig"))
                            continue;
                        Int16 trgType = Convert.ToInt16(subKey.GetValue("KindofTrigger", "0").ToString());
                        RegistryKey checkKey = reg.OpenSubKey(strName);

                        //Date Variable For Calendar Test Trigger
                        string strdataReg = string.Empty;

                        switch (trgType) {
                            case 0:
                                if (!EventLog.SourceExists(sSource))
                                    EventLog.CreateEventSource(sSource, sLog);

                                EventLog.WriteEntry(sSource, "(Task : " + strName + ")Type of Trigger not Founnd ! Check TriggerTest : " + strName +
                            " for Schedulations : " + schName + " in AleScheduler Registry Key", EventLogEntryType.Error);
                                break;
                            //Start of Hard Disk Trigger Test Group
                            case 101:
                                //Case Open Files Trigger Test
                                try {
                                    string path = checkKey.GetValue("Path", string.Empty).ToString();
                                    if (!string.IsNullOrEmpty(path)) {
                                        int DirectoryEnd = path.LastIndexOf("\\");                    //Prendo la Posizione di fine della Path Directory
                                        string directoryPath = path.Substring(0, DirectoryEnd + 1);   //Prendo la path della Directory
                                        int lenTot = ((path.Length) - (DirectoryEnd + 1));
                                        string fileNm = path.Substring(DirectoryEnd + 1, lenTot);
                                        DirectoryInfo dir = new DirectoryInfo(directoryPath);
                                        FileInfo[] files = dir.GetFiles(fileNm);                      //Creo con tutti i file contenuti nella directory in base alla wildcard
                                        if (files.Length <= 0) return false;                          //Se non ci sonoi elementi nell'array non ci sono files per cui non esistono e ritorno
                                        foreach (FileInfo fileToExec in files) {
                                            if (!(AleCheck.Disk_Check.FileNotInUse(fileToExec.FullName)))
                                                return false;
                                        }
                                    } else
                                        EventLog.WriteEntry(sSource, "(Task : " + strName + ")Path Field for Test of Trigger not Founnd !\n Impossible To Test Open Files Trigger!!!\n Check TriggerTest : " + strName + " for Schedulations : " + schName + " in AleScheduler Registry Key", EventLogEntryType.Error);
                                } catch (Exception ee) {
                                    EventLog.WriteEntry(sSource, "(Task : " + strName + ")Error assessing Open Files Trigger Test : " + ee.Message, EventLogEntryType.Error);
                                }
                                break;
                            case 102:
                                //Case Files Exist Trigger Test
                                try {
                                    string path2 = checkKey.GetValue("Path", string.Empty).ToString();
                                    if (!string.IsNullOrEmpty(path2)) {
                                        int DirectoryEnd = path2.LastIndexOf("\\");                    //Prendo la Posizione di fine della Path Directory
                                        string directoryPath = path2.Substring(0, DirectoryEnd + 1);   //Prendo la path della Directory
                                        int lenTot = ((path2.Length) - (DirectoryEnd + 1));
                                        string fileNm = path2.Substring(DirectoryEnd + 1, lenTot);
                                        DirectoryInfo dir = new DirectoryInfo(directoryPath);
                                        FileInfo[] files = dir.GetFiles(fileNm);                            //Creo con tutti i file contenuti nella directory in base alla wildcard
                                        if (files.Length <= 0) return false;                            //Se non ci sonoi elementi nell'array non ci sono files per cui non esistono e ritorno
                                        foreach (FileInfo fileToExec in files) {
                                            if (!(System.IO.File.Exists(fileToExec.FullName)))
                                                return false;
                                        }
                                    } else
                                        EventLog.WriteEntry(sSource, "(Task : " + strName + ")Path Field for Test of Trigger not Founnd !\n Impossible To Test Files Exist Trigger!!!\n Check TriggerTest : " + strName + " for Schedulations : " + schName + " in AleScheduler Registry Key", EventLogEntryType.Error);
                                } catch (Exception ex) {
                                    EventLog.WriteEntry(sSource, "(Task : " + strName + ")Error assessing Files Exist Trigger Test : " + ex.Message, EventLogEntryType.Error);
                                }

                                break;
                            case 103:
                                //Case Files NOT Exist Trigger Test
                                try {
                                    string path3 = checkKey.GetValue("Path", string.Empty).ToString();
                                    if (!string.IsNullOrEmpty(path3)) {
                                        int DirectoryEnd1 = path3.LastIndexOf("\\");                    //Prendo la Posizione di fine della Path Directory
                                        string directoryPath1 = path3.Substring(0, DirectoryEnd1 + 1);   //Prendo la path della Directory
                                        int lenTot1 = ((path3.Length) - (DirectoryEnd1 + 1));
                                        string fileNma = path3.Substring(DirectoryEnd1 + 1, lenTot1);
                                        DirectoryInfo dirC = new DirectoryInfo(directoryPath1);
                                        FileInfo[] filesC = dirC.GetFiles(fileNma);                   //Creo con tutti i file contenuti nella directory in base alla wildcard
                                        foreach (FileInfo fileToCheck in filesC) {
                                            if ((System.IO.File.Exists(fileToCheck.FullName)))
                                                return false;
                                        }
                                    } else
                                        EventLog.WriteEntry(sSource, "(Task : " + strName + ")Path Field for Test of Trigger not Founnd !\n Impossible To Test Files NOT Exist Trigger!!!\n Check TriggerTest : " + strName + " for Schedulations : " + schName + " in AleScheduler Registry Key", EventLogEntryType.Error);
                                } catch (Exception ex) {
                                    EventLog.WriteEntry(sSource, "(Task : " + strName + ")Error assessing Files NOT Exist Trigger Test : " + ex.Message, EventLogEntryType.Error);
                                }
                                break;
                            case 111:
                                //Case Directory Exist Trigger Test
                                string path111 = checkKey.GetValue("Path", string.Empty).ToString();
                                if (!(path111 == string.Empty)) {
                                    if (!(System.IO.Directory.Exists(path111)))
                                        return false;
                                } else
                                    EventLog.WriteEntry(sSource, "(Task : " + strName + ")Path Field for Test of Trigger not Founnd !\n Impossible To Test Directory Exist Trigger!!!\n Check TriggerTest : " + strName + " for Schedulations : " + schName + " in AleScheduler Registry Key", EventLogEntryType.Error);
                                break;
                            case 112:
                                //Case Directory NOT Exist Trigger Test
                                string path112 = checkKey.GetValue("Path", string.Empty).ToString();
                                if (!(path112 == string.Empty)) {
                                    if ((System.IO.Directory.Exists(path112)))
                                        return false;
                                } else
                                    EventLog.WriteEntry(sSource, "(Task : " + strName + ")Path Field for Test of Trigger not Founnd !\n Impossible To Test Directory NOT Exist Trigger!!!\n Check TriggerTest : " + strName + " for Schedulations : " + schName + " in AleScheduler Registry Key", EventLogEntryType.Error);
                                break;
                            case 121:
                                //Hard Disk Test Drive Exist - Trigger Test
                                string drive = checkKey.GetValue("Drive", string.Empty).ToString();
                                if (drive != string.Empty) {
                                    if (!(System.IO.Directory.Exists(drive)))
                                        return false;
                                } else
                                    EventLog.WriteEntry(sSource, "(Task : " + strName + ")Drive Field for Test of Trigger not Founnd !\n Impossible To Test Drive Exist Trigger!!!\n Check TriggerTest : " + strName + " for Schedulations : " + schName + " in AleScheduler Registry Key", EventLogEntryType.Error);
                                break;
                            case 122:
                                //Hard Disk Test Space Availaible - Trigger Test
                                string driveFree = checkKey.GetValue("Drive", "C:").ToString();
                                AleCheck.Disk_Check freeSpace = new AleCheck.Disk_Check();
                                double freeSpaceù = Convert.ToDouble(freeSpace.GetFreeDiskSpace(driveFree));
                                double settedSpace = Convert.ToDouble(checkKey.GetValue("Path", "0").ToString());
                                if (freeSpaceù < settedSpace)
                                    return false;
                                break;
                            //CPU-RAM Triggers Test Group
                            case 201:
                                //CPU Less than a XX%
                                AleCheck.CPU_Check cpu1 = new AleCheck.CPU_Check();
                                if (!(cpu1.CpuUsage < Convert.ToDouble((string)checkKey.GetValue("Usage", "0"))))
                                    return false;
                                break;
                            case 202:
                                //CPU More Than a XX%
                                AleCheck.CPU_Check cpu = new AleCheck.CPU_Check();
                                if ((cpu.CpuUsage < Convert.ToDouble((string)checkKey.GetValue("Usage", "0"))))
                                    return false;
                                break;
                            case 211:
                                //RAM Less Than a XXX Mb
                                AleCheck.CPU_Check ram1 = new AleCheck.CPU_Check();
                                string AvailableRAM = ram1.getAvailableRAM();
                                AvailableRAM = AvailableRAM.Remove(AvailableRAM.Length - 2, 2);
                                if (!(Convert.ToInt32(AvailableRAM) < Convert.ToInt32((string)checkKey.GetValue("Usage", "0"))))
                                    return false;
                                break;
                            case 212:
                                //RAM More Than a XXX Mb
                                AleCheck.CPU_Check ram2 = new AleCheck.CPU_Check();
                                string AvailableRAM2 = ram2.getAvailableRAM();
                                AvailableRAM2 = AvailableRAM2.Remove(AvailableRAM2.Length - 2, 2);
                                if ((Convert.ToInt32(AvailableRAM2) < Convert.ToInt32((string)checkKey.GetValue("Usage", "0"))))
                                    return false;
                                break;
                            //Network Triggers Test Group
                            case 301:
                                //Internet Connection Alive
                                if (!(AleCheck.LAN_Check.PingTest))
                                    return false;
                                break;
                            case 302:
                                //LAN Network Alive
                                if (!(AleCheck.LAN_Check.IsConnectedToInternet))
                                    return false;
                                break;
                            case 303:
                                //Ping IP Success
                                try {
                                    System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
                                    System.Net.NetworkInformation.PingReply pingStatus = ping.Send(System.Net.IPAddress.Parse((string)checkKey.GetValue("IP", string.Empty)));
                                    if (!(pingStatus.Status == System.Net.NetworkInformation.IPStatus.Success))
                                        return false;

                                } catch (Exception ex) {
                                    EventLog.WriteEntry(sSource, "(Task : " + strName + ")Error Executing Ping, Can't Ping given IP Address : " + ex.Message, EventLogEntryType.Error);
                                }
                                break;
                            //User Triggers Test Group
                            case 401:
                                //User Logged >
                                if (!(userCount > Convert.ToInt32((string)checkKey.GetValue("User", string.Empty))))
                                    return false;
                                break;
                            case 402:
                                //User Logged <
                                if (!(userCount < Convert.ToInt32((string)checkKey.GetValue("User", string.Empty))))
                                    return false;
                                break;
                            case 403:
                                //Current User =
                                if (!(Environment.UserName == (string)checkKey.GetValue("User", string.Empty)))
                                    return false;
                                break;
                            //System Triggers Test Group
                            case 501:
                                //Check Idle Time of System
                                if (!(AleCheck.System_Check.IdleTime >= Convert.ToInt32((string)checkKey.GetValue("FSystemTest", "0"))))
                                    return false;
                                break;
                            case 502:
                                //Check Uptime of System
                                if (!(AleCheck.System_Check.UpTime >= Convert.ToInt32((string)checkKey.GetValue("FSystemTest", "0"))))
                                    return false;
                                break;
                            case 503:
                                //Registry Key Exist
                                if (AleCheck.System_Check.RegKeyExist((int)checkKey.GetValue("KeyKind", "1"), (string)checkKey.GetValue("FSystemTest", "0")) != true)
                                    return false;
                                break;
                            case 504:
                                //Registry Key NOT Exist
                                if (AleCheck.System_Check.RegKeyExist((int)checkKey.GetValue("KeyKind", "1"), (string)checkKey.GetValue("FSystemTest", "0")) == true)
                                    return false;
                                break;
                            case 505:
                                //Service Exist
                                if (!(AleCheck.System_Check.IsServiceInstalled((string)checkKey.GetValue("FSystemTest", string.Empty))))
                                    return false;
                                break;
                            case 506:
                                //Service NOT Exist
                                if (AleCheck.System_Check.IsServiceInstalled((string)checkKey.GetValue("FSystemTest", string.Empty)))
                                    return false;
                                break;
                            case 507:
                                //Process Exist
                                if (!(AleCheck.System_Check.ProcessExist((string)checkKey.GetValue("FSystemTest", string.Empty))))
                                    return false;
                                break;
                            case 508:
                                //Process NOT Exist
                                if (AleCheck.System_Check.ProcessExist((string)checkKey.GetValue("FSystemTest", string.Empty)))
                                    return false;
                                break;
                            //Begin Of Calendar Trigger Test
                            case 601:
                                //Today is = To Date
                                strdataReg = ((string)checkKey.GetValue("DateTrigger", string.Empty)).Trim();
                                string strHourFrom = ((string)checkKey.GetValue("FromHourTrigger", string.Empty)).Trim();
                                string strHourTo = ((string)checkKey.GetValue("ToHourTrigger", string.Empty)).Trim();
                                DateTime DateFrom = Convert.ToDateTime(strdataReg + " " + strHourFrom);
                                DateTime DateTo = Convert.ToDateTime(strdataReg + " " + strHourTo);

                                if (!(DateTime.Now > DateFrom && DateTime.Now < DateTo))
                                    return false;
                                break;
                            case 602:
                                //Today isn't equal To Date
                                strdataReg = ((string)checkKey.GetValue("DateTrigger", string.Empty)).Trim();
                                strHourFrom = ((string)checkKey.GetValue("FromHourTrigger", string.Empty)).Trim();
                                strHourTo = ((string)checkKey.GetValue("ToHourTrigger", string.Empty)).Trim();
                                DateFrom = Convert.ToDateTime(strdataReg + " " + strHourFrom);
                                DateTo = Convert.ToDateTime(strdataReg + " " + strHourTo);
                                if ((DateTime.Now > DateFrom && DateTime.Now < DateTo))
                                    return false;
                                break;
                            case 603:
                                //Today is Less Than Date
                                strdataReg = ((string)checkKey.GetValue("DateTrigger", string.Empty)).Trim();
                                strHourFrom = ((string)checkKey.GetValue("FromHourTrigger", string.Empty)).Trim();
                                strHourTo = ((string)checkKey.GetValue("ToHourTrigger", string.Empty)).Trim();
                                DateFrom = Convert.ToDateTime(strdataReg + " " + strHourFrom);
                                DateTo = Convert.ToDateTime(strdataReg + " " + strHourTo);
                                if (!(DateTime.Now < DateFrom && (DateTime.Now.TimeOfDay > DateFrom.TimeOfDay && DateTime.Now.TimeOfDay < DateTo.TimeOfDay)))
                                    return false;
                                break;
                            case 604:
                                //Today is More Than Date
                                strdataReg = ((string)checkKey.GetValue("DateTrigger", string.Empty)).Trim();
                                strHourFrom = ((string)checkKey.GetValue("FromHourTrigger", string.Empty)).Trim();
                                strHourTo = ((string)checkKey.GetValue("ToHourTrigger", string.Empty)).Trim();
                                DateFrom = Convert.ToDateTime(strdataReg + " " + strHourFrom);
                                DateTo = Convert.ToDateTime(strdataReg + " " + strHourTo);
                                if (!(DateTime.Now > DateFrom && (DateTime.Now.TimeOfDay > DateFrom.TimeOfDay && DateTime.Now.TimeOfDay < DateTo.TimeOfDay)))
                                    return false;
                                break;
                        }

                        checkKey.Close();
                    }
                    reg.Close();
                } //Closing using block

            } catch (Exception eee) {
                EventLog.WriteEntry(sSource,"Generic Error during Trigger Test evaluation !" + Environment.NewLine +
                    "Error : " + eee.Message + Environment.NewLine +
                    "Details : " + eee.StackTrace + Environment.NewLine, EventLogEntryType.Error);
            }
            return true;
        }
        #endregion
        #region Test_Passed_Times & Test_Period
        bool Test_Passed_Times(ulong NumberOfTimes, ulong PassedTimes)
        {
            if (NumberOfTimes == 0 || PassedTimes == 0)
                return true;

            if (PassedTimes < NumberOfTimes)
                return true;
            else
                return false;
        }

        bool Test_Period_Time(string StartTime, string StopTime)
        {
            //Test If range of Time is OK
            DateTime now = DateTime.Now;
            int ora = now.Hour;
            int min = now.Minute;
            int starthour = (StartTime != string.Empty) ? Convert.ToInt32(StartTime.Substring(0, 2)) : 0;
            int startmin = (StartTime != string.Empty) ? Convert.ToInt32(StartTime.Substring(3, 2)) : 0;
            int stophour = (StopTime != string.Empty) ? Convert.ToInt32(StopTime.Substring(0, 2)) : 0;
            int stopmin = (StopTime != string.Empty) ? Convert.ToInt32(StopTime.Substring(3, 2)) : 0;
            DateTime date1 = new DateTime(now.Year, now.Month, now.Day, ora, min, 0);
            DateTime date2 = new DateTime(now.Year, now.Month, now.Day, starthour, startmin, 0);
            DateTime date3 = new DateTime(now.Year, now.Month, now.Day, stophour, stopmin, 0);

            if (StartTime != string.Empty && StopTime != string.Empty)
            {

                int result1 = DateTime.Compare(date1, date2);
                int result2 = DateTime.Compare(date1, date3);
                if (result1 < 0 || result2 > 0)
                    return false;
            }
            else if (StartTime != string.Empty)
            {
                int result1 = DateTime.Compare(date1, date2);
                if (result1 < 0)
                    return false;
            }
            else if (StopTime != string.Empty)
            {
                int result2 = DateTime.Compare(date1, date3);
                if (result2 > 0)
                    return false;
            }

            return true;
        }
        #endregion

        private void log(bool textLog, string Message, EventLogEntryType type,string Taskname,string pathlog)
        {
            if (!EventLog.SourceExists(sSource))
                EventLog.CreateEventSource(sSource, sLog);

            EventLog.WriteEntry(sSource, Message,type);
            if (textLog)
                AleUtil.appLog.WriteTextLog(Message, pathlog, Taskname);
        }

        protected override void OnSessionChange(SessionChangeDescription changeDescription)
        {
            base.OnSessionChange(changeDescription);
            switch (changeDescription.Reason)
            {
                case SessionChangeReason.SessionLogon:
                    userCount += 1;
                    Check_Start_SessionChange(1);
                    break;

                case SessionChangeReason.SessionLogoff:
                    userCount -= 1;
                    Check_Start_SessionChange(2);
                    break;
                case SessionChangeReason.RemoteConnect:
                    userCount += 1;
                    Check_Start_SessionChange(5);
                    break;

                case SessionChangeReason.RemoteDisconnect:
                    userCount -= 1;
                    Check_Start_SessionChange(6);
                    break;
                case SessionChangeReason.SessionLock:
                    Check_Start_SessionChange(3);
                    break;

                case SessionChangeReason.SessionUnlock:
                    Check_Start_SessionChange(4);
                    break;

                default:
                    break;
            }
        }

         protected override void OnCustomCommand(int command)
         {
         base.OnCustomCommand(command);
         if (command == (int)commands.HUP)
         {
             refreshConfig();
             launchCounter.Clear();
         }
        }
        #region SessionChangeStartProcess
        private void Check_Start_SessionChange(int typeSession)
        {

                //Variable Declarations and initialize the to default
                bool forceInteractWithDesktop = false;
                string strExeName = string.Empty;
                bool SendMail = false;
                bool Disabled = false;
                string pathexe = string.Empty;
                string strArgument = string.Empty;
                bool LogText = false;
                string LogPath = String.Empty;
                uint timeOut = 0;
                uint WinMode = 1;

                if (Monitor.TryEnter(_locker, TimeSpan.FromSeconds(5))) {
                    try {
                        //Loop for examine every Schedulations item in the regestry
                        foreach (KeyValuePair<string, Dictionary<string, string>> strName in aSettings) {
                            Dictionary<string, string> subKey = strName.Value;
                            string strNameREG = strName.Key;

                            if ((subKey == null))
                                continue;

                            //First of all get the Schedule Type Code 
                            int schType = Convert.ToInt16(subKey["ScheduleType"]);
                            //if ScheduleType is not equal to 6(On SessionChange Type) Exit
                            if (schType != 6)
                                continue;

                            //Read the kind of On SessionChange Task
                            int onSessionType = Convert.ToInt16(subKey["OnSessionChange"]);

                            //if regestry setting is not equal to typeSession exit
                            if (onSessionType != typeSession)
                                continue;

                            //Read The Variable from regestry for ScheduleType 6 (Session Change)Task
                            strExeName = subKey["FileToRun"];
                            SendMail = Convert.ToBoolean(subKey["SendMail"]);
                            Disabled = Convert.ToBoolean(subKey["Disabled"]);
                            pathexe = subKey["PathEXE"];
                            strArgument = subKey["Arguments"];
                            timeOut = Convert.ToUInt32(subKey["Timeout"]);
                            uint TriggerTest = Convert.ToUInt16(subKey["TriggerTest"]);
                            LogText = Convert.ToBoolean(subKey["LogFiles"]);
                            LogPath = subKey["LogDirectory"];
                            forceInteractWithDesktop = Convert.ToBoolean(subKey["ForceInteractWithDesktop"]);
                            WinMode = Convert.ToUInt32(subKey["WindowMode"]);

                            //Start Process Code with Force Interact with Desktop for ScheduleType 6 (Session Change)

                            //Test if Trigger Test is Enabled - If Yes do the trigger Test
                            if ((TriggerTest == 0) || (TriggerTest > 0 && Trigger_Test(strNameREG))) {
                                foreach (FileInfo fileToExec in listFilesInExecutable(strExeName)) {
                                    Thread t = new Thread(delegate() { Start_Scheduletions_Process(forceInteractWithDesktop, strNameREG, fileToExec.Name, pathexe, strArgument, SendMail, timeOut, LogText, LogPath, WinMode); });
                                    t.Start();
                                }

                            }

                        } //End of the loop through Regestry keys

                    } catch (Exception ex) {
                        EventLog.WriteEntry("Error during task evaluation in session change event : " + ex.Message, EventLogEntryType.Error);
                    } finally {
                        Monitor.Exit(_locker);
                    }
                }
        }

        #endregion

         private void stopWatchProcess_EventArrived(object sender, EventArrivedEventArgs e) {
            string processName = (string)e.NewEvent.Properties["ProcessName"].Value;
            if (!processName.EndsWith(".exe")) processName += ".exe";
             watchProcessRun(2, processName);
        }

        private void startWatchProcess_EventArrived(object sender, EventArrivedEventArgs e) {
            //EventLog.WriteEntry(sSource, "Process started: " + e.NewEvent.Properties["ProcessName"].Value, EventLogEntryType.Information);
            string processName = (string)e.NewEvent.Properties["ProcessName"].Value;
            if (!processName.EndsWith(".exe")) processName += ".exe";
            watchProcessRun(1,processName);
        }

        private void watchProcessRun(int typeHappened, string Process) {
            string sKindWatcher = "All Event";

            if (typeHappened < 3) {
                sKindWatcher = (typeHappened == 1) ? "Process Start" : "Process Stop";
            }

            if(Monitor.TryEnter(_locker, TimeSpan.FromSeconds(5))) {
            //Read if there is a schedulation for Process Watcher event
            try {
                //Loop for examine every Schedulations item in the in Memory Settings
                foreach (KeyValuePair<string, Dictionary<string, string>> strName in aSettings) {
                    Dictionary<string, string> tmp = strName.Value;
                    Int16 schtype = Convert.ToInt16(tmp["ScheduleType"]);
                    //If readed Schedulation is FileSystemWatcher Schedulation
                    if (schtype == 8) {
                        string strExeName = tmp["FileToRun"];
                        string ProcessCheck = tmp["WatchFileDir"];
                        int type = int.Parse(tmp["WatcherType"]);
                        //Check First what kind of event has happened, if All Event(3) start Process
                        if ((typeHappened == type || type == 3) && (ProcessCheck.Equals(Process))) {
                            EventLog.WriteEntry(sSource, "New " + sKindWatcher + " event fired, Process Name : " + Process, EventLogEntryType.Information);
                            bool ForceToInteractWithDesktop = Convert.ToBoolean(tmp["ForceInteractWithDesktop"]);
                            uint timeOut = Convert.ToUInt32(tmp["Timeout"]);
                            uint WinMode = Convert.ToUInt32(tmp["WindowMode"]);
                            uint TriggerTest = Convert.ToUInt32(tmp["TriggerTest"]);
                            bool TextLog = Convert.ToBoolean(tmp["LogFiles"]);
                            bool SendMail = Convert.ToBoolean(tmp["SendMail"]);
                            bool Disabled = Convert.ToBoolean(tmp["Disabled"]);
                            //Check Trigger and eventually start the process
                            if (!Disabled && (TriggerTest == 0 || Trigger_Test(strName.Key))) {
                                //Start Schedulation Process in a New Thread
                                foreach (FileInfo fileToExec in listFilesInExecutable(strExeName))
                                    new Thread(delegate() { Start_Scheduletions_Process(ForceToInteractWithDesktop, strName.Key, fileToExec.FullName, tmp["PathEXE"], tmp["Arguments"], SendMail, timeOut, TextLog, tmp["LogDirectory"], WinMode); }).Start();
                            }
                        }
                    }
                }
            } catch (Exception ex) {
                //Log Error in event logger
                System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
                string message = "Error on Process watcher event : " + ex.Message + Environment.NewLine +
                    "Type : " + sKindWatcher + Environment.NewLine +
                    string.Format("Function : {0}, Line : {1}, Column : {2}", trace.GetFrame(0).GetMethod().Name, trace.GetFrame(0).GetFileLineNumber(), trace.GetFrame(0).GetFileColumnNumber()) + Environment.NewLine +
                    "StackTrace : " + Environment.NewLine + ex.StackTrace;
                EventLog.WriteEntry(sSource, message, EventLogEntryType.Error);

            } finally {
                Monitor.Exit(_locker);
            }
            } //End of TryEnter lock of the monitor
        }

        private FileInfo[] listFilesInExecutable(string strExeName) {
            int DirectoryEnd = strExeName.LastIndexOf("\\");
            string directoryPath = strExeName.Substring(0, DirectoryEnd + 1);
            int lenTot = ((strExeName.Length) - (DirectoryEnd + 1));
            string fileNm = strExeName.Substring(DirectoryEnd + 1, lenTot);
            FileInfo[] files = new FileInfo[1];
            files[0] = new FileInfo(strExeName.Replace("*","").Replace("?",""));
            try {
                DirectoryInfo dir = new DirectoryInfo(directoryPath);
                files = dir.GetFiles(fileNm);
            } catch (Exception) { }
            return files;
        }

        private bool isValidDate(string date) {
            string MatchExp = @"(\d{2})/(\d{2})/(\d{2,4})";
            System.Text.RegularExpressions.Match theMatch = System.Text.RegularExpressions.Regex.Match(date, MatchExp);
            return theMatch.Success;
        }
    }
}
